package com.gdteam.kernel.timer.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.tapestry5.ioc.annotations.EagerLoad;
import org.apache.tapestry5.ioc.annotations.Inject;

import com.gdteam.kernel.main.ServiceManager;
import com.gdteam.kernel.timer.TimerJob;
import com.gdteam.kernel.timer.TimerManager;


@EagerLoad
public class DefaultTimerManager implements TimerManager {

    private List<TimerJob> jobs = new ArrayList<TimerJob>();
    
    //java.util.Timer stuff
    private Map<TimerJob, TimerTask> taskMap = new HashMap<TimerJob, TimerTask>();
    private Timer timer = null;
    
    private boolean started = false;
    
    @Inject
    public DefaultTimerManager(ServiceManager mgr) {
        mgr.registerOperations(this);
    }
    
    public void addTimerJob(TimerJob job) throws IllegalStateException {
        if (!this.jobs.contains(job)) {
            
            if (this.timer != null) {
                this.jobs.add(job);
                
                TimerTask task = new JobTask(job);
                this.taskMap.put(job, task);
                
                this.scheduleJob(job);
            } else {
                throw new IllegalStateException("Timer manager is not started");
            }
        }
    }

    public TimerJob getTimerJob(String id) {
        for (TimerJob job : this.jobs) {
            if (job.getId().equals(id)) {
                return job;
            }
        }
        
        return null;
    }

    public void removeTimerJob(TimerJob job) {
        if (this.jobs.contains(job)) {
            this.taskMap.get(job).cancel();
            this.taskMap.remove(job);
            this.jobs.remove(job);
        }
    }

    public String getName() {
        return FQN;
    }

    public void start() {
        
        if (!started) {
            if (this.timer == null) {
                this.timer = new Timer(FQN);
                
                //Schedule all jobs
                for (TimerJob job : this.jobs) {
                    this.scheduleJob(job);
                }
            }
            this.started = true;
        }
    }

    public void stop() {
        if (started) {
            if (this.timer != null) {
                //Suspend all jobs, and cancel their tasks
                for (TimerJob job : this.jobs) {
                    job.suspend();
                    this.taskMap.get(job).cancel();
                }
                this.jobs.clear();
                this.taskMap.clear();
                
                this.timer.purge();
                this.timer.cancel();
                this.timer = null;
            }
            this.started = false;
        }
       
    }
    
    /**
     * Schedule one job
     * @param job
     */
    private void scheduleJob(TimerJob job) {
       if (this.timer == null) {
           throw new IllegalStateException("Timer is not started");
       }
       
       TimerTask task = this.taskMap.get(job);
       
       if (job.getPeriod() != null) {
           this.timer.schedule(task, job.getDelay(), job.getPeriod());
       } else {
           this.timer.schedule(task, job.getDelay());
       }
       
    }
    
    public boolean isStarted() {
        return this.started;
    }
    
    private class JobTask extends TimerTask {

        private TimerJob job;

        public JobTask(TimerJob job) {
            this.job = job;
        }
        
        @Override
        public void run() {
            this.job.perform();
        }
    }
}
